package com.zmn.oms.zmn.business.impl.orderworkingrecord;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.JSON;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.base.pilot.common.dto.pilot.PilotCheckQuery;
import com.zmn.base.pilot.common.enums.PilotTypeEnum;
import com.zmn.base.pilot.dubbo.interfaces.pilot.PilotRemoteService;
import com.zmn.base.plat.engine.common.constant.DubboConsts;
import com.zmn.biz.mds.common.constant.AgentType;
import com.zmn.biz.mds.common.constant.CallTypeConstant;
import com.zmn.biz.mds.common.constant.HangUpContants;
import com.zmn.biz.mds.common.constant.MediaSceneConstants;
import com.zmn.biz.mds.common.dio.VoiceDetectionDIO;
import com.zmn.biz.mds.common.enums.AppEnum;
import com.zmn.biz.mds.dubbo.interfaces.detection.MediaDetectionRemoteService;
import com.zmn.biz.mds.dubbo.interfaces.util.DubboConst;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.work.OrderWorkListBService;
import com.zmn.oms.common.constant.MessageQueueTagConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.constant.ServItemTypeEnum;
import com.zmn.oms.common.dio.orderworkingrecord.OrderWorkingRecordDIO;
import com.zmn.oms.common.dro.orderworkingrecord.HistoryVoiceDetectionDRO;
import com.zmn.oms.common.enums.WorkingRecordNodeEnum;
import com.zmn.oms.common.exception.OmsBusinessException;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.orderworkingrecord.OrderWorkingRecord;
import com.zmn.oms.model.entity.orderworkingrecord.OrderWorkingRecordQuery;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import com.zmn.oms.services.interfaces.orderworkingrecord.OrderWorkingRecordService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.orderworkingrecord.OrderWorkingRecordBService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zmn.oms.common.enums.WorkingRecordNodeEnum.*;


/**
 * 工程师上门录音业务接口类
 *
 * @author chengguang
 * @date 2022/07/20
 */
@Service
@Slf4j
public class OrderWorkingRecordBServiceImpl implements OrderWorkingRecordBService {

    @Resource
    private OrderWorkingRecordService orderWorkingRecordService;

    @Resource
    private OrderLogBService orderLogBService;

    @Resource
    private OrderWorkService orderWorkService;

    @Resource
    private OrderWorkListBService orderWorkListBService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private PilotRemoteService pilotRemoteService;

    @DubboReference(version = DubboConst.INTERFACE_VERSION, check = false)
    private MediaDetectionRemoteService mediaDetectionRemoteService;

    ThreadPoolExecutor executor = new ThreadPoolExecutor(3,3,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    /**
     * 现场录音标签
     */
    private static final Integer LIVE_RECORDING_INSPECT_LABEL = 7;

    /**
     * 现场录音媒体场景id
     */
    private static final Integer LIVE_RECORDING_MEDIA_DETECT_SCENE = 9582;

    @Override
    public Boolean addOrderWorkingRecord(OrderWorkingRecordDIO orderWorkingRecordDIO) {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkingRecordDIO.getOrderId(), orderWorkingRecordDIO.getWorkId());

        if (Objects.isNull(orderWork)) {
            throw new OmsBusinessException("工单不存在");
        }

        if (!Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING)) {
            throw new OmsBusinessException("工单状态不在进行中不能录音");
        }

        OrderWorkingRecord orderWorkingRecord = BeanUtil.copyProperties(orderWorkingRecordDIO, OrderWorkingRecord.class);
        orderWorkingRecord.setRecordEndTime(new Date(orderWorkingRecordDIO.getRecordEndTimeStamp()));
        orderWorkingRecord.setRecordStartTime(new Date(orderWorkingRecordDIO.getRecordStartTimeStamp()));
        orderWorkingRecordService.insert(orderWorkingRecord);

        // 保存日志
        OrderLog orderLog = new OrderLog();
        String content = "录音节点：" + WorkingRecordNodeEnum.getNodeName(orderWorkingRecord.getRecordNode()) + "</br>" +
                "录音时长：" + DateUtil.getDurationDesc(Long.valueOf(orderWorkingRecord.getRecordDuration())) + "</br>" +
                "录音状态：" + (Objects.equals(orderWorkingRecord.getRecordStatus(), GlobalConsts.YES) ? "完成" : "中断") + "</br>" +
                "APP系统：" + (Objects.equals(orderWorkingRecordDIO.getAppPlat(), GlobalConsts.YES) ? "IOS" : "Android") + "</br>" +
                "版本号：V" + orderWorkingRecordDIO.getDisplayVersion() + "</br>";
        orderLog.setOrderId(orderWorkingRecord.getOrderId());
        orderLog.setWorkId(orderWorkingRecord.getWorkId());
        orderLog.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
        orderLog.setOperatorTypeName(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_MASTER));
        orderLog.setOperatorId(Long.valueOf(orderWorkingRecord.getEngineerId()));
        orderLog.setOperator(orderWork.getMasterName());
        orderLog.setContent(content);
        orderLog.setTypeName(WorkingRecordNodeEnum.getNodeName(orderWorkingRecord.getRecordNode()));
        orderLog.setMasterId(orderWorkingRecord.getEngineerId());
        orderLog.setCreateTime(new Date());
        orderLogBService.save(orderLog);

        // 校验试点语音质检
        CompletableFuture.runAsync(() -> {
            PilotCheckQuery pilotCheckQuery = PilotCheckQuery.builder()
                    .cityId(orderWork.getCityId())
                    .servCategId(orderWork.getServCategId())
                    .categId(orderWork.getShowCategId())
                    .channelId(orderWork.getChannelId())
                    .pilotTypeId(PilotTypeEnum.DOOR_RECORD.getId()).build();
            ResponseDTO<Boolean> responseDTO = pilotRemoteService.checkPilotByQuery(pilotCheckQuery);
            if (!responseDTO.isSuccess()) {
                log.error("pilotRemoteService.checkPilotByQuery 失败，入参：{}", pilotCheckQuery);
                return;
            }

            Boolean flag = responseDTO.getData();
            if (flag) {
                // 推送语音质检服务
                asyncVoiceDetection(orderWork, orderWorkingRecord);
            }
        },executor);

        return Boolean.TRUE;
    }

    @Override
    public void asyncHistoryVoiceDetection(HistoryVoiceDetectionDRO historyVoiceDetectionDRO) {

        OrderWorkQuery orderWorkQuery = new OrderWorkQuery();
        orderWorkQuery.setChannelIdList(Collections.singletonList(historyVoiceDetectionDRO.getChannelId()));
        orderWorkQuery.setCityIdList(Collections.singletonList(historyVoiceDetectionDRO.getCityId()));
        orderWorkQuery.setServCategId(Collections.singletonList(historyVoiceDetectionDRO.getServCategId()));
        // visitTime:"2022-09-05 00:00:00,2022-09-05 23:59:59"
        orderWorkQuery.setVisitTime(historyVoiceDetectionDRO.getVisitTime());
        orderWorkQuery.setShowCategTwoIdList(Collections.singletonList(historyVoiceDetectionDRO.getCategId()));
        orderWorkQuery.setWorkStatusList(Arrays.asList(OrderStatusConsts.WORK_STATUS_VISIT,
                OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE,
                OrderStatusConsts.WORK_STATUS_COMPLETE,
                OrderStatusConsts.WORK_STATUS_CHECKOUT,
                OrderStatusConsts.WORK_STATUS_ACCOUNT));
        orderWorkQuery.setPermit(GlobalConsts.NO);
        orderWorkQuery.setPageSize(5000);
        List<EsOrderWork> esOrderWorks = orderWorkListBService.listPageOrderWorkByQuery(orderWorkQuery);
        if (CollectionUtils.isEmpty(esOrderWorks)) {
            log.error("orderWorkListBService.listPageOrderWorkByQuery esOrderWorks为空 ");
            return;
        }
        Map<Long, EsOrderWork> esOrderWorkMap = esOrderWorks.stream().collect(Collectors.toMap(EsOrderWork::getOrderId, Function.identity()));

        // 查询订单的录音数据
        Set<Long> orderIds = esOrderWorkMap.keySet();
        OrderWorkingRecordQuery orderWorkingRecordQuery = new OrderWorkingRecordQuery();
        orderWorkingRecordQuery.setOrderIds(orderIds);
        orderWorkingRecordQuery.setPageSize(5000);
        List<OrderWorkingRecord> orderWorkingRecords = orderWorkingRecordService.listPageByQuery(orderWorkingRecordQuery);
        if (CollectionUtils.isEmpty(orderWorkingRecords)) {
            log.error("orderWorkingRecordService.listPageByQuery orderWorkingRecords为空 ");
            return;
        }
        orderWorkingRecords.forEach(orderWorkingRecord -> {
            EsOrderWork esOrderWork = esOrderWorkMap.get(orderWorkingRecord.getOrderId());
            OrderWork orderWork = new OrderWork();
            orderWork.setOrderId(esOrderWork.getOrderId());
            orderWork.setMasterName(esOrderWork.getMasterName());
            orderWork.setBizType(esOrderWork.getBizType());
            orderWork.setChannelName(esOrderWork.getChannelName());
            orderWork.setType(esOrderWork.getType());
            orderWork.setResultStatus(esOrderWork.getResultStatus());
            orderWork.setServItemType(esOrderWork.getServItemType());
            orderWork.setStatus(esOrderWork.getStatus());
            asyncVoiceDetection(orderWork, orderWorkingRecord);
        });

    }

    private void asyncVoiceDetection(OrderWork orderWork, OrderWorkingRecord orderWorkingRecord) {
        VoiceDetectionDIO voiceDetectionDIO = new VoiceDetectionDIO();
        voiceDetectionDIO.setBizRecordId(orderWorkingRecord.getRecordId().toString());
        voiceDetectionDIO.setHangUp(HangUpContants.OTHER_HANG_UP);
        voiceDetectionDIO.setCallType(CallTypeConstant.ON_SITE_RECORD);
        voiceDetectionDIO.setDuration(orderWorkingRecord.getRecordDuration());
        voiceDetectionDIO.setRecordTime(cn.hutool.core.date.DateUtil.format(orderWorkingRecord.getRecordStartTime(),
                DatePattern.NORM_DATETIME_PATTERN));
        voiceDetectionDIO.setAgentId(orderWorkingRecord.getEngineerId());
        voiceDetectionDIO.setAgentType(AgentType.ENGINEER);
        voiceDetectionDIO.setAgentName(orderWork.getMasterName());
        Map<String, Object> dictDataMap = new HashMap<>(8);
        dictDataMap.put("orderStatus", OrderStatusConsts.getWorkStatusName(Objects.isNull(orderWork.getStatus()) ?
                GlobalConsts.NONE : orderWork.getStatus()));
        dictDataMap.put("bizType", orderWork.getBizType());
        dictDataMap.put("orderChannel", orderWork.getChannelName());
        dictDataMap.put("priceType", ServItemTypeEnum.getServItemTypeName(orderWork.getServItemType()));
        dictDataMap.put("liveRecordNode", WorkingRecordNodeEnum.getNodeName(orderWorkingRecord.getRecordNode()));
        dictDataMap.put("workOrderType", orderWork.getType());
        dictDataMap.put("workOrderResult", orderWork.getResultStatus());
        dictDataMap.put("inspectLabel", LIVE_RECORDING_INSPECT_LABEL);
        voiceDetectionDIO.setDictData(dictDataMap);
        voiceDetectionDIO.setNotifyTopic(MessageQueueTopicConstant.ZMN_TOPIC_OMS);
        voiceDetectionDIO.setNotifyTag(MessageQueueTagConsts.WORKING_RECORD_QUALITY);
        voiceDetectionDIO.setAppBizNo(orderWork.getOrderId().toString());
        voiceDetectionDIO.setRecordUrl(orderWorkingRecord.getRecordUrl());
        voiceDetectionDIO.setMediaScene(getMediaSceneMapping(orderWorkingRecord.getRecordNode()));
        voiceDetectionDIO.setMediaDetectScene(LIVE_RECORDING_MEDIA_DETECT_SCENE);
        voiceDetectionDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_MASTER);
        voiceDetectionDIO.setOperatorId(Long.valueOf(orderWorkingRecord.getEngineerId()));
        voiceDetectionDIO.setOperator(orderWork.getMasterName());
        voiceDetectionDIO.setAppId(AppEnum.APP_OMS.getAppId());
        voiceDetectionDIO.setAppName(AppEnum.APP_OMS.getAppName());
        log.info("推送语音质检服务，入参 {}", JSON.toJSONString(voiceDetectionDIO));
        mediaDetectionRemoteService.asyncVoiceDetection(voiceDetectionDIO);
    }


    /**
     * 描述: 录音节点和媒体场景id映射
     *
     * @param recordNode 录音节点
     * @return {@link Integer }
     * @author chengguang
     * @since 2022/09/05
     */
    private static Integer getMediaSceneMapping(Integer recordNode) {

        if (Objects.equals(recordNode, COME_DOOR.getCode())) {
            return MediaSceneConstants.SCENE_CONFIRM_ENGINEER_RECORD;
        }
        if (Objects.equals(recordNode, START_QUOTATION.getCode())) {
            return MediaSceneConstants.SCENE_PRICE_RECORD;
        }
        if (Objects.equals(recordNode, CONFIRM_REPORT.getCode())) {
            return MediaSceneConstants.SCENE_CONFIRM_REPORT_RECORD;
        }
        if (Objects.equals(recordNode, DISCOUNTS_ACTIVITIES.getCode())) {
            return MediaSceneConstants.SCENE_DISCOUNT_RECORD;
        }
        if (Objects.equals(recordNode, APPLY_DISCOUNTS.getCode())) {
            return MediaSceneConstants.SCENE_APPLY_DISCOUNT_RECORD;
        }
        if (Objects.equals(recordNode, SERVICE_COMPLETION.getCode())) {
            return MediaSceneConstants.SCENE_SERVICE_COMPLETE_ENGINEER_RECORD;
        }
        if (Objects.equals(recordNode, WAITING_PAYMENT.getCode())) {
            return MediaSceneConstants.SCENE_WAIT_PAY_RECORD;
        }
        if (Objects.equals(recordNode, START_MAINTENANCE.getCode())) {
            return MediaSceneConstants.SCENE_BEGIN_REPAIR_RECORD;
        }
        if (Objects.equals(recordNode, SELECT_SERVICE_ITEM.getCode())) {
            return MediaSceneConstants.SCENE_CHOOSE_SERV_ITEM_RECORD;
        }

        return GlobalConsts.NONE;
    }
}
